package MySQL::Query;

use strict;
use warnings;
use base qw(MySQL::Query::Base);

__PACKAGE__->mk_ro_accessors(qw(sql tree));
__PACKAGE__->mk_accessors(qw(parser));

use Carp;
use DBIx::MyParsePP;

my $token_class = 'DBIx::MyParsePP::Token';
my $rule_class 	= 'DBIx::MyParsePP::Rule';

sub init {
      my $self = shift;

      $self->parser( new DBIx::MyParsePP ) unless $self->parser;

      if ( my $query = $self->sql ) {
            $self->parse( $query );
      }
}

sub parse {
      my ($self , $query) = @_;
      $self->{tree} = $self->parser->parse( $query );
      $self->{sql} = $query;
      return $self;
}

sub tokens {
      my ($self , $tree) = @_;
      $tree ||= $self->tree;
      my @tokens = ();
      for (my $i = 0; $i <= $#{$tree}; $i++) {
	    if (ref $tree->[$i] eq $rule_class) {
		  my $res = $self->tokens($tree->[$i]);
                  push @tokens , @$res if ref $res eq 'ARRAY';
	    } elsif (ref $tree->[$i] eq $token_class) {
		  push @tokens , $tree->[$i];
	    }
      }
      return \@tokens;
}

sub walk {
      my ($self, $cb, $tree) = @_;
    
      $tree ||= $self->tree->getRoot;
      die "no tree, use either parse method or sql option of the constructor"
            unless $tree;

      my $rv = $cb->( $tree );
      return unless $rv;

      foreach my $child ( $tree->children ) {
            $self->walk( $cb, $child );
      }
}

sub as_builder {
      my $self = shift;
      
      require MySQL::Query::Tables;
      require MySQL::Query::Extract;
      my $tables = MySQL::Query::Tables->new( tree => $self );
      my $extract = MySQL::Query::Extract->new( tree => $self , tables => $tables );
      
      return $extract->extract_all;
}


=head1 NAME

MySQL::Query - Module for holding & making operations on parsed SQL tree 


=head1 SYNOPSIS
      
      use MySQL::Query;
      
      #create parsed tree using DBIx::MyParsePP;
      my $tree = MySQL::Query->new(sql => 'SELECT 1 FROM table'); 
      
      #get's you a list of tokens
      my $tokens = $tree->tokens();
      
      #interact with MyParsePP methods
      my $where_clause = $tree->tree->getWhere();
      
=head1 DESCRIPTION
      
      This is an alpha realese. The following methods is subject to change in future.
      
=head1 METHODS

=head2 new(%config)
     
      Call new() to create a new object:
            my $tree = MySQL::Query->new(sql => 'SELECT 1 FROM table');
            
      Or you could construct it with already parsed tree
            my $tree = MySQL::Query->new(tree => $tree);
     
=head2 init($sql)
      
      Initiates new parsed tree
            $tree->init($sql);
      
=head2 tree()
      
      Maps to MyParsePP object
            my $myparse_obj = $tree->tree;
            my $sql = $myparse->sql;
            
=head2 tokens($tree)

      Returns an arrayref of tokens found in $tree
            my $tokens = $tree->tokens($tree);
      Or, if no $tree specified, it uses the one found in $tree->tree();
            my $tokens = $tree->tokens();

=head1 AUTHOR

Mikhail Maluyk <mikhail.maluyk@gmail.com>

=cut

1;
